package com.yh.csx.bsf.ods.controller;

import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.Map.Entry;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.yh.csx.bsf.core.db.DbConn;
import com.yh.csx.bsf.core.thread.ThreadPool;
import com.yh.csx.bsf.core.util.ConvertUtils;
import com.yh.csx.bsf.core.util.LogUtils;
import com.yh.csx.bsf.core.util.StringUtils;

import com.yh.csx.bsf.ods.CanelFullLoadStarter;
import com.yh.csx.bsf.ods.StragtegyProvider;
import com.yh.csx.bsf.ods.fullload.TaskManager;
import com.yh.csx.bsf.ods.fullload.TaskManager.SubTask;
import com.yh.csx.bsf.ods.fullload.TaskManager.Task;
import com.yh.csx.bsf.ods.meta.OdsSyncAdapter;

import lombok.var;

@Controller
@RequestMapping("/")
public class TaskController {
	final static String DATETIME_FORMAT="yyyy-MM-dd HH:mm:ss";
	@Autowired
	private TaskManager taskManager;
	
	@Autowired
	Map<String, OdsSyncAdapter> syncers;
	@Autowired
	StragtegyProvider stragtegyProvider;
	private ExecutorService executorService=Executors.newFixedThreadPool(4);
	
	@GetMapping("/")
	@ResponseBody
	public String info() {
		if (taskManager != null) {
			return processInfo().replace("\r\n", "<br/>");
		}
		return "任务未启动";
	}

	@RequestMapping(value = "/sync.do", method = { RequestMethod.POST })
	public String sync(String tables) {
		ThreadPool.System.submit("web-sync", () -> {
			this.fullLoad(tables);
		});
		return "redirect:/";
	}
	/**
	 * 清理任务
	 * */
	@RequestMapping(value = "/clear", method = { RequestMethod.GET })
	public String clear(String tables) {
		taskManager.clear();
		return "redirect:/";
	}
	@GetMapping("/sync")
	public String sync() {
		return "sync";
	}

	@GetMapping("/createViews")
	public String createViews() {
		Optional.of(syncers).get().forEach((name, syncer) -> {
			try {
				syncer.createViews();
			} catch (Throwable e) {
				LogUtils.error(this.getClass(), "ods", "【更新视图】异常", e);
			}
		});
		return "/";
	}

	private String processInfo() {
		String info = " [总任务]" + taskManager.getTaskCount() + " [运行中]" + taskManager.getRunningCount() + " [完成]"
				+ taskManager.getDoneCount() + " [待执行]" + taskManager.getWaitingCount() + " [出错]"
				+ taskManager.getErrorCount() + "\r\n\r\n";
		// 刷新进度
		for (TaskManager.Task t : taskManager.getTasks().values()) {
			info += t.getTargetTable();
			double progress=t.getProgress();
			if ( progress != -1 ) {
				info += "[" + t.getProgress() * 100 + "%] ";
				info +="[开始时间："+( new SimpleDateFormat(DATETIME_FORMAT)).format(t.getStartTime());
				if(progress>=1) {
					info +=",结束时间："+( new SimpleDateFormat(DATETIME_FORMAT)).format(t.getEndTime());
					info+=",用时:"+t.getUsedTime()+"s";
				}
				info +="]\r\n ";
			} else {
				info += "[未开始]\r\n";
			}
		}
		return info;
	}

	public void fullLoad(String tables) {
		try {
			String[] lsTables = tables.split(",");			
			LogUtils.info(CanelFullLoadStarter.class, "ods", "任务数量：" + lsTables.length);
			final CountDownLatch latch = new CountDownLatch(lsTables.length);			
			for (String t : lsTables) {
				executorService.submit(() -> {
					if (!StringUtils.isEmpty(t)) {
						try {
							for (var db : stragtegyProvider.getDbs()) {
								try (DbConn dbConn = stragtegyProvider.getDb(db)) {
									if (dbConn != null) {
										List<Map<String, Object>> rs = dbConn.executeList(
												"select distinct table_name from information_schema.columns where table_schema =?",
												new Object[] { db });
										for (var r : rs) {
											var table = ConvertUtils.convert(r.get("TABLE_NAME"), String.class);
											if (stragtegyProvider.getTargetTable(db, table).equals(t)) {
												TaskManager.SubTask subTask = new TaskManager.SubTask();
												subTask.setDb(db);
												subTask.setTable(table);
												subTask.setTargetTable(t);
												taskManager.putSubTask(subTask);
											}
										}
									} else {
										LogUtils.info(CanelFullLoadStarter.class, "ods", "数据源未配置:" + db);
									}
								}
							}
						} catch (Exception e) {
							LogUtils.error(CanelFullLoadStarter.class, "ods", "数据任务初始化异常" , e);
						}
					}
					latch.countDown();
				});
			}
			latch.await();

			String mysqltables = "";
			for (Entry<String, Task> task : taskManager.getTasks().entrySet()) {
				for (SubTask subTask : task.getValue().getSubTasks().values()) {
					mysqltables += subTask.getDb() + "." + subTask.getTable();
				}
			}
			LogUtils.info(CanelFullLoadStarter.class, "ods", "准备实际mysql导入表:" + mysqltables);
			
			while (taskManager.getWaitingCount() == 0) {
				try {
					Thread.sleep(5 * 1000);
				} catch (Exception exp) {
				}
			}
			LogUtils.info(CanelFullLoadStarter.class, "ods", "当前导入已启动, http://loalhost:8081/ 查看进度");
		} catch (Exception e) {
			LogUtils.error(CanelFullLoadStarter.class, "ods", "严重错误", e);
		}
	}
}
